﻿using System;

namespace SoftwareConsulting.BI11.NumericalMethods.Statistics
{
    /// <summary>
    /// Класс получения ранга корреляции Спирмана
    /// </summary>
    public class SpearmanCorrelationRank
    {
        private double _result;
        
        /// <summary>
        /// Конструктор класса
        /// </summary>
        /// <param name="sample1">выборка 1</param>
        /// <param name="sample2">выборка 2</param>
        /// <param name="sampleSize">размер выборок</param>
        public SpearmanCorrelationRank(double[] sample1, double[] sample2, int sampleSize)
        {
            _result = 0;
            sample1 = (double[])sample1.Clone();
            sample2 = (double[])sample2.Clone();
            sample1 = rankx(sample1, sampleSize);
            sample2 = rankx(sample2, sampleSize);
            PearsonCorrelation corelP = new PearsonCorrelation(sample1, sample2, sampleSize);
            _result =corelP.GetSolution() ;
        }

        /// <summary>
        /// Находит ранг указанной выборки
        /// </summary>
        /// <param name="sample">выборка</param>
        /// <param name="sampleSize">размер выборки</param>
        private static double[] rankx(double[] sample,int sampleSize)
        {            
            double tmp = 0;
            int tmpi = 0;
            double[] r = new double[0];
            int[] c = new int[0];
            //подготавливаем
            if (sampleSize <= 1)
            {
                sample[0] = 1;
                return sample;
            }
            r = new double[sampleSize - 1 + 1];
            c = new int[sampleSize - 1 + 1];
            int i = 0;
            for (i = 0; i <= sampleSize - 1; i++)
            {
                r[i] = sample[i];
                c[i] = i;
            }            
            //сортируем {R,C}            
            if (sampleSize != 1)
            {
                i = 2;
                do
                {
                    int t = i;
                    while (t != 1)
                    {
                        int k = t / 2;
                        if (r[k - 1] >= r[t - 1])
                        {
                            t = 1;
                            continue;
                        }                        
                        tmp = r[k - 1];
                        r[k - 1] = r[t - 1];
                        r[t - 1] = tmp;
                        tmpi = c[k - 1];
                        c[k - 1] = c[t - 1];
                        c[t - 1] = tmpi;
                        t = k;                        
                    }
                    i++;
                }
                while (i <= sampleSize);
                i = sampleSize - 1;
                do
                {
                    tmp = r[i];
                    r[i] = r[0];
                    r[0] = tmp;
                    tmpi = c[i];
                    c[i] = c[0];
                    c[0] = tmpi;
                    int t = 1;
                    while (t != 0)
                    {
                        int k = 2 * t;
                        if (k > i)
                        {
                            t = 0;
                            continue;
                        }
                        if ((k < i) && (r[k] > r[k - 1]))
                            k++;                        
                        if (r[t - 1] >= r[k - 1])
                        {
                            t = 0;
                            continue;
                        }                        
                        tmp = r[k - 1];
                        r[k - 1] = r[t - 1];
                        r[t - 1] = tmp;
                        tmpi = c[k - 1];
                        c[k - 1] = c[t - 1];
                        c[t - 1] = tmpi;
                        t = k;                                                
                    }
                    i--;
                }
                while (i >= 1);
            }
            //вычисляем связанные ранги            
            i = 0;
            while (i <= sampleSize - 1)
            {
                int j = i + 1;
                while (j <= sampleSize - 1)
                {
                    if (r[j] != r[i])
                        break;
                    j++;
                }
                for (int k = i; k <= j - 1; k++)
                {
                    r[k] = 1 + ((double)(i + j - 1)) / (double)(2);
                }
                i = j;
            }
            //обратно к X
            for (i = 0; i <= sampleSize - 1; i++)
            {
                sample[c[i]] = r[i];
            }
            return sample;
        }

        /// <summary>
        /// Возвращает решение
        /// </summary>        
        public double GetSolution()
        {
            return _result;
        }
    }
}
